package com.nexgo.payment.ui.main;

import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;

import com.nexgo.lamp.LampOperate;
import com.nexgo.oaf.apiv3.DeviceEngine;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.nexgo.oaf.apiv3.emv.EmvHandler;
import com.nexgo.payment.BuildConfig;
import com.nexgo.payment.aop.annotation.RunOnMainThread;
import com.nexgo.payment.aop.annotation.RunOnWorkThread;
import com.nexgo.payment.api.ApiDeviceEngine;
import com.nexgo.payment.constrant.OfflineState;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.constrant.SettlePrintState;
import com.nexgo.payment.constrant.SysConstant;
import com.nexgo.payment.constrant.UploadType;
import com.nexgo.payment.constrant.ValueKey;
import com.nexgo.payment.databases.DataSource;
import com.nexgo.payment.databases.SettleInfo;
import com.nexgo.payment.databases.Signature;
import com.nexgo.payment.databases.TransRecord;
import com.nexgo.payment.util.AidCapkUtils;
import com.nexgo.payment.util.StringUtils;
import com.nexgo.payment.util.TransUtils;
import com.nexgo.payment.util.UIUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java8.util.Optional;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 首页操作接口实现
 *
 * @author 谭忠扬-YuriTam//xiaox 2017/9/15 下午4:17
 * @time 2017年9月5日
 */
public class MainPresenter implements MainContract.Presenter {
    private Logger mLog = LoggerFactory.getLogger(MainPresenter.class.getSimpleName());

    private final MainContract.View mView;
    private final DataSource mRepository;
    private final Handler mHandler;
    private DeviceEngine mDeviceEngine;
    private boolean isFirstTimes = true;
    private boolean isFirstDownAidTimes = true;
    private boolean isFirstDownCapkTimes = true;
    private boolean mUploadResult = true;
    private final EmvHandler mSdkEmvHandler ;

    public MainPresenter(@NonNull MainContract.View view, @NonNull DataSource repository) {
        mView = checkNotNull(view);
        mRepository = checkNotNull(repository);
        mView.setPresenter(this);
        mHandler = new Handler(Looper.getMainLooper());
        mDeviceEngine = ApiDeviceEngine.getInstance();
        mSdkEmvHandler = ApiDeviceEngine.getDefaultEmvHandler();

    }

    @Override
    @RunOnWorkThread
    public void start() {

        if (BuildConfig.LOG_DEBUG) {
            if (mSdkEmvHandler.getAidListNum() == 0) {
                mSdkEmvHandler.setAidParaList(AidCapkUtils.getProductionAidList());
            }
            if (mSdkEmvHandler.getCapkListNum() == 0) {
                mSdkEmvHandler.setCAPKList(AidCapkUtils.getProductionCapkList());
            }
            mRepository.setParamValue(PreferencesConstants.CURRENT_OPERATOR_NO,"01");
            mRepository.setParamValue(PreferencesConstants.IS_NEED_LOGIN,"0");
            mRepository.syncParamValue();
        }
        //重置按键时间，以防外部修改了时间再返回本应用
        UIUtils.clearLastClickEvent();
        //判断是否未拔卡，是则提示拔卡
        if (checkCardExist()) {
            return;
        }
        //判断是否上笔交易是否未打印完成
        if (checkNeedPrintLastTrans()) {
            return;
        }
        String operator = mRepository.getParamValue(PreferencesConstants.CURRENT_OPERATOR_NO);
        if (!(TransUtils.isAdminOperator(operator) || TransUtils.isSystemOperator(operator))) {
            //判断是否需要签到
            if (checkNeedLogin()) {
                return;
            }
            //判断是否结算单没有打印
            if (checkNeedPrintLastSettle()) {
                return;
            }
  /*          //需要批上送
            if (checkNeedBatchUpload()) {
                return;
            }*/
            if (mUploadResult) {
                //分别检查是否需要下载AID及CAPK，是则跳转去自动下载
                if (checkNeedLoadAid()) {
                    return;
                }
                if (checkNeedLoadCapk()) {
                    return;
                }
/*                //后台处理码
                if (checkNeedDoPosCommand()) {
                    return;
                }
                //QPS卡BIN B
                if (checkNeedQpsBinB()) {
                    return;
                }
                //QPS卡BIN C
                if (checkNeedQpsBinC()) {
                    return;
                }*/
/*                //联机电子签名上送
                if (checkEsUploadLastOnlineButNotCurrent()) {
                    return;
                }
                //离线/脱机交易上送
                if (checkOfflineUpload()) {
                    return;
                }*/
            }
            mUploadResult = true;
        }
        LampOperate.getInstance().transIdle();
        isFirstTimes = false;
        isFirstDownAidTimes = false;
        isFirstDownCapkTimes = false;
    }

    /**
     * 检查是否需要打印结算单
     *
     * @return
     */
    private boolean checkNeedPrintLastSettle() {
        Optional<SettleInfo> optional = Optional.ofNullable(mRepository.getSettleInfo())
                .filter(settleInfo -> settleInfo.getIsBatchUploadComplete())
                .filter(settleInfo -> SettlePrintState.values()[settleInfo.getPrintState()].equals(SettlePrintState.NONE));
        optional.ifPresent(settleInfo -> {
            mLog.debug("需要打印结算单");
            postMainThread(() -> mView.showNeedPrintLastSettle());
        });
        return optional.isPresent();
    }

    /**
     * 检查是否要打印上一笔，用于第一次启动app
     *
     * @return
     */
    private boolean checkNeedPrintLastTrans() {
        if (isFirstTimes) {
            Optional<TransRecord> optional = Optional.ofNullable(mRepository.getLastSuccessfulTransRecord())
                    .filter(transRecord -> !transRecord.getIsPrinted());
            optional.ifPresent(transRecord -> {
                mLog.debug("需要打印上一笔交易记录");
                postMainThread(() -> mView.showNeedPrintLastTrans());
            });
            return optional.isPresent();
        }
        return false;
    }

    /**
     * 检查后台命令
     *
     * @return
     */
    private boolean checkNeedDoPosCommand() {
        int command = 0;
        Object value = mRepository.getValue(ValueKey.POS_COMMAND);
        if (value != null) {
            command = (int) value;
        }
        if (command != 0x00) {
            mLog.debug("后台命令 {}", command);
            switch (command) {
                case 0x01:
                    postMainThread(() -> mView.showNeedLoadCapk());
//                    postMainThread(() -> mView.showNeedParamDown());
                    break;
                case 0x02:
                    postMainThread(() -> mView.showNeedLoadAid());
//                    postMainThread(() -> mView.showNeedUploadState());
                    break;
                case 0x03:
                    postMainThread(() -> mView.showNeedRfParamDown());
//                    postMainThread(() -> mView.showNeedLogin());
                    break;
                case 0x04:
                    postMainThread(() -> mView.showNeedLoadAid());
                    postMainThread(() -> mView.showNeedLoadCapk());
                    break;
                case 0x05:
//                    postMainThread(() -> mView.showNeedParamDown());
                    postMainThread(() -> mView.showNeedLoadCapk());
                    postMainThread(() -> mView.showNeedRfParamDown());
                    break;
                case 0x06:
                    postMainThread(() -> mView.showNeedLoadAid());
                    postMainThread(() -> mView.showNeedRfParamDown());
                    break;
                case 0x07:
                    postMainThread(() -> mView.showNeedLoadCapk());
                    postMainThread(() -> mView.showNeedLoadAid());
                    postMainThread(() -> mView.showNeedRfParamDown());
                    break;
/*                case 0x09:
                    postMainThread(() -> mView.showNeedRfParamDown());
                    break;
                case 0x0B:
                    postMainThread(() -> mView.showNeedQpsBinB());
                    break;
                case 0x0C:
                    postMainThread(() -> mView.showNeedQpsBinC());
                    break;*/
                default:
                    break;
            }
            mRepository.setValue(ValueKey.POS_COMMAND, null);
            return true;
        }
        return false;
    }

    /**
     * 检查是否需要批上送
     *
     * @return
     */
    private boolean checkNeedBatchUpload() {
        Optional<SettleInfo> optional = Optional.ofNullable(mRepository.getSettleInfo())
                .filter(settleInfo -> !settleInfo.getIsBatchUploadComplete());
        optional.ifPresent(settleInfo -> {
            mLog.debug("需要批上送");
            postMainThread(() -> mView.showNeedBatchUpload());
        });
        return optional.isPresent();
    }

    /**
     * 检查QPS是否需要BinC
     *
     * @return
     */
    private boolean checkNeedQpsBinC() {
        if (!"1".equals(mRepository.getParamValue(PreferencesConstants.QPS_BIN_C_INIT_FLAG))) {
            mLog.debug("需要下载QpsBinC");
            postMainThread(() -> mView.showNeedQpsBinC());
            return true;
        }
        return false;
    }

    /**
     * 检查QPS是否需要BinB
     *
     * @return
     */
    private boolean checkNeedQpsBinB() {
        if (!"1".equals(mRepository.getParamValue(PreferencesConstants.QPS_BIN_B_INIT_FLAG))) {
            mLog.debug("需要下载QpsBinB");
            postMainThread(() -> mView.showNeedQpsBinB());
            return true;
        }
        return false;
    }

    /**
     * 检查离线上送
     *
     * @return
     */
    private boolean checkOfflineUpload() {
        long num = mRepository.getTotalOfflineNeverUploadNum();
        mLog.debug("存在{}笔未上送离线交易或者离线电子签名", num);
        if (num >= Integer.parseInt(StringUtils.firstNonEmpty(mRepository.getParamValue(PreferencesConstants.OFFLINE_TRANS_UPLOAD_NUMBER), "10"))) {
            mLog.debug("需要上送离线交易或者离线电子签名");
            postMainThread(() -> mView.showUpload(UploadType.ALL_NEVER_UPLOAD_OFFLINE));
            return true;
        }
        return false;
    }

    /**
     * 检查最后一笔电子签名上送，非当前交易
     *
     * @return
     */
    private boolean checkEsUploadLastOnlineButNotCurrent() {
        Optional<Signature> optional = Optional.ofNullable(mRepository.getLastSuccessfulTransRecord())
                .filter(transRecord -> OfflineState.ONLINE.equals(OfflineState.values()[transRecord.getOfflineState()]))
                .map(transRecord -> mRepository.getLastOnlineButNotCurrentSignature(transRecord.getTraceNum()));
        optional.ifPresent(signature -> {
            mLog.debug("需要上送最后一笔联机交易的电子签名");
            postMainThread(() -> mView.showUpload(UploadType.ES_ONLINE_LAST_BUT_NOT_CURRENT));
        });
        return optional.isPresent();
    }

    /**
     * 检查是否需要下载CAPK
     *
     * @return
     */
    private boolean checkNeedLoadCapk() {
        if (mDeviceEngine.getEmvHandler(SysConstant.EMV_OPERAT_PATH).getCapkListNum() == 0&&isFirstDownCapkTimes) {
            mLog.debug("需要下载CAPK");
            postMainThread(() -> mView.showNeedLoadCapk());
            isFirstDownCapkTimes=false;
            return true;
        }
        return false;
    }

    /**
     * 检查是否需要下载AID
     *
     * @return
     */
    private boolean checkNeedLoadAid() {
        if (mDeviceEngine.getEmvHandler(SysConstant.EMV_OPERAT_PATH).getAidListNum() == 0&& isFirstDownAidTimes) {
            mLog.debug("需要下载AID");
            postMainThread(() -> mView.showNeedLoadAid());
            isFirstDownAidTimes=false;
            return true;
        }
        return false;
    }

    /**
     * 检查是否需要重新签到
     *
     * @return
     */
    private boolean checkNeedLogin() {
        if ("1".equals(mRepository.getParamValue(PreferencesConstants.IS_NEED_LOGIN))) {
            mLog.debug("需要重新签到");
            postMainThread(() -> mView.showNeedLogin());
            return true;
        }
        return false;
    }

    /**
     * 检查是否未拔卡
     *
     * @return
     */
    private boolean checkCardExist() {
        if (mDeviceEngine.getCardReader().isCardExist(CardSlotTypeEnum.ICC1) ||
                mDeviceEngine.getCardReader().isCardExist(CardSlotTypeEnum.RF)) {
            mLog.debug("需要提示拔卡");
            postMainThread(() -> mView.showCardExist());
            return true;
        }
        return false;
    }

    @Override
    public void pause() {

    }

    @Override
    public void destroy() {
        LampOperate.getInstance().closeAll();
    }

    @RunOnMainThread
    private void postMainThread(Runnable runnable) {
        runnable.run();
    }

    @Override
    public void setUploadResult(boolean isSuccessful) {
        mUploadResult = isSuccessful;
    }
}
